// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/win/foreground_helper.h"

#include "base/logging.h"
#include "ui/gfx/win/window_impl.h"

namespace ui {

// static
HRESULT ForegroundHelper::SetForeground(HWND window)
{
    DCHECK(::IsWindow(window));
    ForegroundHelper foreground_helper;
    return foreground_helper.ForegroundHotKey(window);
}

HRESULT ForegroundHelper::ForegroundHotKey(HWND window)
{
    // This implementation registers a hot key (F22) and then
    // triggers the hot key.  When receiving the hot key, we'll
    // be in the foreground and allowed to move the target window
    // into the foreground too.

    set_window_style(WS_POPUP);
    Init(NULL, gfx::Rect());

    static const int kHotKeyId = 0x0000baba;
    static const int kHotKeyWaitTimeout = 2000;

    // Store the target window into our USERDATA for use in our
    // HotKey handler.
    window_ = window;
    RegisterHotKey(hwnd(), kHotKeyId, 0, VK_F22);

    // If the calling thread is not yet a UI thread, call PeekMessage
    // to ensure creation of its message queue.
    MSG msg = { 0 };
    PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);

    // Send the Hotkey.
    INPUT hotkey = { 0 };
    hotkey.type = INPUT_KEYBOARD;
    hotkey.ki.wVk = VK_F22;
    if (1 != SendInput(1, &hotkey, sizeof(hotkey))) {
        LOG(WARNING) << "Failed to send input; GetLastError(): " << GetLastError();
        return E_FAIL;
    }

    // There are scenarios where the WM_HOTKEY is not dispatched by the
    // the corresponding foreground thread. To prevent us from indefinitely
    // waiting for the hotkey, we set a timer and exit the loop.
    SetTimer(hwnd(), kHotKeyId, kHotKeyWaitTimeout, NULL);

    // Loop until we get the key or the timer fires.
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);

        if (WM_HOTKEY == msg.message)
            break;
        if (WM_TIMER == msg.message) {
            SetForegroundWindow(window);
            break;
        }
    }

    UnregisterHotKey(hwnd(), kHotKeyId);
    KillTimer(hwnd(), kHotKeyId);
    DestroyWindow(hwnd());

    return S_OK;
}

// Handle the registered Hotkey being pressed.
void ForegroundHelper::OnHotKey(int id, UINT vcode, UINT modifiers)
{
    SetForegroundWindow(window_);
}

} // namespace ui
